import json
import psycopg2

from jose import jwt, ExpiredSignatureError, JWTError

from django.db.models import Q
from django.http import JsonResponse
from django.utils import timezone
from django.views import View
from django.utils.decorators import method_decorator
from django.views.decorators.http import require_http_methods
from django.conf import settings

from gongyequ.models import SurveyItemFile
from gongyequ.models import SurveyItem
from gongyequ.models import SurveyItemUser
from gongyequ.models import SurveyItemApproval
from gongyequ.utils.page import get_pagination
from gongyequ.decorator import login_required
from gongyequ.decorator import permission_required
from gongyequ.models import User


def _get_user(request):
    token = request.META.get('HTTP_AUTHORIZATION')
    if not token:
        return JsonResponse(dict(meaasge='missing "Bearer Token" header'))

    try:
        token = token.replace('Bearer ', '')
        jwt_token = jwt.decode(token, settings.SECRET_KEY)
        user = User.objects.get(id=jwt_token.get('sub'))
        return user
    except User.DoesNotExist:
        return JsonResponse(dict(message='not found', status=False, code=400))
    except ExpiredSignatureError:
        return JsonResponse(dict(message='token 已过期，请重新登录', status=False, code=401))
    except JWTError:
        return JsonResponse(dict(message='bad token', status=False, code=401))


@method_decorator(login_required(), name='dispatch')
@method_decorator(permission_required('admin'), name='dispatch')
class SurveyView(View):
    def get(self, request, id=None):
        if id is not None:
            return self._get_surveyitem(request, id)
        else:
            return self._list_surveyitems(request)

    def post(self, request, id=None, action=None):
        if action:
            if action == 'rejected':
                return self._surveyitem_rejected(request, id)
            elif action == 'assessment':
                return self._surveyitem_assessment(request, id)
            elif action == 'approved':
                return self._surveyitem_approved(request, id)
            elif action == 'reportdata':
                return self._surveyitem_report(request, id)

        return self._create_surveyitem(request)

    def delete(self, request, id):
        return self._delete_surveyitem(request, id)

    def _create_surveyitem(self, request):
        """提交项目问卷
        POST /industrialapi/surveyitem

        Body{
            name='工业区名称'
            city='城市'
            address={"name":"上海市杨浦区杨树浦路"}
            radius=500  //拓展半径  数值再500-200
            mode='评估模式' [可选] 如：城市公共功能、城市服务功能、X模式等
            infrastructure=['水通'：true，'电通'：true，] // 多选 基础设施评估
            network={   //路网密段
                '主干路':'800km'，
                '次干路':'800km'，
                '支路':'800km'，
                'files':[
                    {
                    'url':'data/12/6464646/1.jpg',
                    'filename':'1.jpg'
                    },
                    {
                    'url':'data/12/6464646/2.jpg',
                    'filename':'2.jpg'
                    }
                ]
            }
            internal_network={ // 内部网络多样性
                '车行连接度'：'80%'，
                '车行整合度'：'80%'，
                '车行选择度'：'80%'，
                ....
            }
            park_safety={  // 工业区各项环境安全度指标
                           // 包含以下内容：城市环境、土壤环境、大气环境、水环境、声环境、光环境、热环境
                '光环境安全度':'一星级'，
                '热环境安全度':'一星级'，
                'files':[{'url':'xx/xx/xx.jpg','filename':'xx.jog'}]
                .....
            }
            house_safety={  // 房屋质量安全度
                            // 包含以下内容：结构安全性、沉溺程度、使用状况
                '结构安全性':'完好'，
                '沉溺程度':'均匀沉降'，
                'files':[{'url':'xx/xx/xx.jpg','filename':'xx.jog'}]
                .....
            }
            indoor_safety={   // 室内空气安全度
                              // 包含以下内容：有毒有害气体、总挥发性有机物含量、可吸入颗粒物含量
                '有毒有害气体':'基本无'，
                '总挥发性有机物含量':'基本无'，
                '可吸入颗粒物含量':'基本无'，
                'files':[{'url':'xx/xx/xx.jpg','filename':'xx.jog'}]
                .....
            }
            photos={"files":[ // 建筑物照片，不得少于20张
                {'url':'xx/xx/xx.jpg','filename':'xx.jog'},
                {'url':'xx/xx/xx.jpg','filename':'xx.jog'},
                {'url':'xx/xx/xx.jpg','filename':'xx.jog'},
                ....
                ]}
        }
        """
        data = json.loads(request.body.decode('utf-8'))
        infrastructure = data.get('infrastructure')
        network = data.get('network')
        internal_network = data.get('internal_network')
        env_safety = data.get('env_safety')
        house_safety = data.get('house_safety')
        indoor_safety = data.get('indoor_safety')
        radius = data.get('radius')

        create_ars = dict(
            infrastructure=infrastructure,
            network=network,
            internal_network=internal_network,
            env_safety=env_safety,
            house_safety=house_safety,
            indoor_safety=indoor_safety,
        )

        required_field = ['name', 'city', 'address', 'radius', 'mode']
        for field in required_field:
            value = data.get(field)
            if not value:
                raise Exception(f'{field}未填写！')

            create_ars[field] = value

        if int(radius) > 2000 or int(radius) < 500:
            return JsonResponse(dict(message='半径范围在2000-500之内', status=False, code=400, data=[]))

        survey_item = SurveyItem.objects.create(**create_ars)

        files = data.get('photos')
        to_insert = []
        for file in files.get('files'):
            to_insert.append(SurveyItemFile(file=file.get('url'), filename=file.get('filename'), survey=survey_item))

        # if len(to_insert) < 20:
        #     raise Exception('图片不能小于20张！')

        SurveyItemFile.objects.bulk_create(to_insert)

        SurveyItemUser.objects.create(user=_get_user(request), survey=survey_item)

        SurveyItemApproval.objects.create(survey=survey_item)

        serialize_data = dict(message='ok', status=True, code=200)
        serialize_data['data'] = survey_item.serialize_detail()

        return JsonResponse(data=serialize_data)

    def _get_surveyitem(self, request, id):
        """获取指定项目
        GET /industrialapi/surveyitem/<int:id>
        """
        try:
            survey = SurveyItem.objects.get(id=id)
        except SurveyItem.DoesNotExist:
            return JsonResponse(dict(message='not found', status=False, code=400, data=[]))

        data = dict(message='ok', status=True, code=200)
        data['data'] = survey.serialize_detail()

        return JsonResponse(data=data)

    def _list_surveyitems(self, request):
        """项目列表
        GET /industrialapi/surveyitem

        Query String:
            mode='评估模式'   // 城市功能功能、城市服务功能、产业升级转型、生态环境修复、X模式
            status='审核状态' // 待审核、评估中、评估完成、审核不通过
            q='工业区名称' or '工业区地址'
        """
        qs = SurveyItem.objects.select_related('approval').filter(is_active=False)

        q = request.GET.get('q')
        if q:
            qs = qs.filter(Q(name__icontains=q) | Q(address__icontains=q))

        mode = request.GET.get('mode')
        if mode:
            qs = qs.filter(mode=mode)

        status = request.GET.get('status')
        if status:
            qs = qs.filter(approval__status=status)

        data = dict(message='ok', status=True, code=200)
        page, _, pagination = get_pagination(request, qs)

        data_list = []
        for survey in page:
            data_list.append(survey.serialize_list())

        data['data'] = data_list
        data['pagination'] = pagination

        return JsonResponse(data=data)

    def _surveyitem_rejected(self, request, id):
        """审核不通过项目
        POST /industrialapi/surveyitem/<int:id>/rejected

        Body{
            note='不通过原因' //审核不通过时必须填写原因
        }
        """
        data = json.loads(request.body.decode('utf-8'))

        try:
            survey = SurveyItemApproval.objects.get(survey_id=id)
        except SurveyItemApproval.DoesNotExist:
            return JsonResponse(dict(message='not found', status=False, code=400, data=[]))

        note = data.get('note')
        if not note:
            return JsonResponse(dict(message='不通过原因必填！', status=False, code=400, data=[]))

        survey.status = SurveyItemApproval.STATUS.rejected
        survey.approver = _get_user(request)
        survey.note = note
        survey.approved_at = timezone.now()
        survey.save()

        return JsonResponse(dict(message='ok', status=True, code=200, data=[]))

    def _surveyitem_assessment(self, request, id):
        """评估中
        POST /industrialapi/surveyitem/<int:id>/assessment
        """
        try:
            survey = SurveyItemApproval.objects.get(survey_id=id)
        except SurveyItemApproval.DoesNotExist:
            return JsonResponse(dict(message='not found', status=False, code=400, data=[]))

        survey.status = SurveyItemApproval.STATUS.assessment
        survey.approver = _get_user(request)
        survey.approved_at = timezone.now()
        survey.save()

        return JsonResponse(dict(message='ok', status=True, code=200, data=[]))

    def _surveyitem_approved(self, request, id):
        """审核完成
        POST /industrialapi/surveyitem/<int:id>/approved
        # TODO 具体逻辑待定
        """
        try:
            survey = SurveyItemApproval.objects.get(survey_id=id)
        except SurveyItemApproval.DoesNotExist:
            return JsonResponse(dict(message='not found', status=False, code=400, data=[]))

        survey.status = SurveyItemApproval.STATUS.approved
        survey.approver = _get_user(request)
        survey.approved_at = timezone.now()
        survey.save()

        return JsonResponse(dict(message='ok', status=True, code=200, data=[]))

    def _surveyitem_report(self,request, id):
        """报告
        POST /industrialapi/surveyitem/<int:id>/reportdata
        """
        try:
            SurveyItem.objects.get(id=id)
        except SurveyItem.DoesNotExist:
            return JsonResponse(dict(message='not found', status=False, code=400, data=[]))

        conn = psycopg2.connect(**settings.RAWDATABASE)
        cur = conn.cursor()
        cur.execute('SELECT * FROM "gongyeyuanqu_data".gongyequ_reportdata where survey_id=%s' % id )
        rows = cur.fetchone()

        return JsonResponse(dict( message='ok', status=True, code=200, data=rows[1]))

    def _delete_surveyitem(self, request, id):
        """删除项目
        DELETE /industrialapi/surveyitem/<int:id>
        """
        try:
            survey = SurveyItem.objects.get(id=id)
        except SurveyItem.DoesNotExist:
            return JsonResponse(dict(message='not found', status=False, code=400, data=[]))

        if survey.is_active:
            return JsonResponse(dict(message='已经是删除状态！', status=False, code=400, data=[]))

        survey.is_active = True
        survey.save()

        return JsonResponse(dict(message='ok', status=True, code=200, data=[]))


@require_http_methods(['GET'])
@login_required()
def history_assessment(request):
    """历史评估
    GET /industrialapi/surveyitem/history

    Query String:
        mode='评估模式'   // 城市功能功能、城市服务功能、产业升级转型、生态环境修复、X模式
        status='审核状态' // 待审核、评估中、评估完成、审核不通过
        q='工业区名称' or '工业区地址'

    * 如果是 admin 就展示所有，普通用户就展示自己申请过的
    """
    qs = SurveyItemUser.objects.filter(survey__is_active=False)

    user = _get_user(request)
    if user.is_admin:
        qs = qs.select_related('survey', 'user').all()
    else:
        qs = qs.filter(user=user).select_related('survey', 'user').all()

    q = request.GET.get('q')
    if q:
        qs = qs.filter(Q(survey__name__icontains=q) | Q(survey__address__icontains=q))

    mode = request.GET.get('mode')
    if mode:
        qs = qs.filter(survey__mode=mode)

    status = request.GET.get('status')
    if status:
        qs = qs.filter(survey__approval__status=status)

    data = dict(message='ok', status=True, code=200)
    page, _, pagination = get_pagination(request, qs)

    data_list = []
    for survey in page:
        data_list.append(survey.serialize())

    data['data'] = data_list
    data['pagination'] = pagination

    return JsonResponse(data=data)
